home *** CD-ROM | disk | FTP | other *** search
/ PC Media 7 / PC MEDIA CD07.iso / share / prog / cm / cmhash.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-06  |  9.8 KB  |  405 lines

  1. // CmHash.cpp
  2. // -----------------------------------------------------------------
  3. // Compendium - C++ Container Class Library
  4. // Copyright (C) 1992-1994, Glenn M. Poorman, All rights reserved
  5. // -----------------------------------------------------------------
  6. // Hash table implementation.
  7. // -----------------------------------------------------------------
  8.  
  9. #include <cm/include/cmhash.h>
  10.  
  11.  
  12. // "CmHashTable" is the default table constructor.
  13. //
  14. CmHashTable::CmHashTable(unsigned sz)
  15. {
  16.   _total   = 0;
  17.   _buckets = new CmHashBucket[sz];
  18.   _size    = (_buckets != NULL) ? sz : 0;
  19. }
  20.  
  21.  
  22. // "CmHashTable" is the table copy constructor.
  23. //
  24. CmHashTable::CmHashTable(const CmHashTable& T)
  25. {
  26.   _total   = 0;
  27.   _buckets = new CmHashBucket[T._size];
  28.   _size    = (_buckets != NULL) ? T._size : 0;
  29.   copy(T);
  30. }
  31.  
  32.  
  33. // "CmHashTable" is the table destructor.
  34. //
  35. CmHashTable::~CmHashTable()
  36. {
  37.   removeAll();
  38.   delete[] _buckets;
  39. }
  40.  
  41.  
  42. // "=" assignment operator copies the contents of the specified
  43. // table into this table.
  44. //
  45. CmHashTable& CmHashTable::operator=(const CmHashTable& T)
  46. {
  47.   if (&T != this)
  48.   {
  49.     removeAll();
  50.     delete[] _buckets;
  51.     _total   = 0;
  52.     _buckets = new CmHashBucket[T._size];
  53.     _size    = (_buckets != NULL) ? T._size : 0;
  54.     copy(T);
  55.   }
  56.   return *this;
  57. }
  58.  
  59.  
  60. // "add" adds the specified object to the hash table.
  61. //
  62. Bool CmHashTable::add(CmObject* pObj)
  63. {
  64.   if (!pObj) return FALSE;
  65.   Bool success = _buckets[pObj->hash(_size)].append(pObj);
  66.   if (success) _total++;
  67.   return success;
  68. }
  69.  
  70.  
  71. // "remove" removes the first occurrence of an object that isEqual
  72. // to the specified object from the table.
  73. //
  74. Bool CmHashTable::remove(CmObject* pObj)
  75. {
  76.   if (!pObj) return FALSE;
  77.   Bool success = _buckets[pObj->hash(_size)].remove(pObj, ownsObjects());
  78.   if (success) _total--;
  79.   return success;
  80. }
  81.  
  82.  
  83. // "lookup" returns the first occurrence of an object which isEqual
  84. // to the specified object.
  85. //
  86. CmObject* CmHashTable::lookup(CmObject* pObj) const
  87. {
  88.   if (!pObj) return FALSE;
  89.   return _buckets[pObj->hash(_size)].lookup(pObj);
  90. }
  91.  
  92.  
  93. // "contains" checks to see if an object that isEqual to the specified
  94. // object exists in the table.
  95. //
  96. Bool CmHashTable::contains(CmObject* pObj) const
  97. {
  98.   if (!pObj) return FALSE;
  99.   return (_buckets[pObj->hash(_size)].lookup(pObj) == NULL) ? FALSE : TRUE;
  100. }
  101.  
  102.  
  103. // "occurrences" returns the number of objects in the table
  104. // isEqual to the specified object.
  105. //
  106. unsigned CmHashTable::occurrences(CmObject* pObj) const
  107. {
  108.   if (!pObj) return FALSE;
  109.   CmHashTableIterator iterator(*this);
  110.   unsigned            num = 0;
  111.   while (!iterator.done())
  112.     if (iterator.next()->isEqual(pObj)) num++;
  113.   return num;
  114. }
  115.  
  116.  
  117. // "removeAll" removes all objects from the table.
  118. //
  119. void CmHashTable::removeAll()
  120. {
  121.   for (int ii = 0; ii < _size; ii++)
  122.     _buckets[ii].removeAll(ownsObjects());
  123.   _total = 0;
  124. }
  125.  
  126.  
  127. // "resize" resizes the hash table.
  128. //
  129. Bool CmHashTable::resize(unsigned newSize)
  130. {
  131.   if (newSize <= 0) newSize = 1;
  132.  
  133.   int           newTotal   = 0;
  134.   CmHashBucket *newBuckets = new CmHashBucket[newSize];
  135.   if (!newBuckets) return FALSE;
  136.  
  137.   CmHashTableIterator iterator(*this);
  138.   while (!iterator.done())
  139.   {
  140.     CmObject *pObj = iterator.next();
  141.     newBuckets[pObj->hash(newSize)].append(pObj);
  142.     newTotal++;
  143.   }
  144.  
  145.   delete[] _buckets;
  146.   _size    = newSize;
  147.   _buckets = newBuckets;
  148.   _total   = newTotal;
  149.   return TRUE;
  150. }
  151.  
  152.  
  153. // "isEmpty" checks to see if any objects are contained in this table.
  154. //
  155. Bool CmHashTable::isEmpty() const
  156. {
  157.   Bool empty = TRUE;
  158.   int  ii    = 0;
  159.   while (ii < _size && empty == TRUE)
  160.     if (_buckets[ii].size() > 0) empty = FALSE;
  161.   return empty;
  162. }
  163.  
  164.  
  165. // "newIterator" creates and returns a new hash table iterator.
  166. //
  167. CmIterator* CmHashTable::newIterator() const
  168. {
  169.   return new CmHashTableIterator(*this);
  170. }
  171.  
  172.  
  173. // "write" writes the array objects to the specified reserve file.
  174. //
  175. Bool CmHashTable::write(CmReserveFile& file) const
  176. {
  177.   if (!writeBase(file))    return FALSE;            // Write base container.
  178.   if (!file.write(_total)) return FALSE;            // Write number of objects.
  179.  
  180.   Bool success  = TRUE;
  181.   CmHashTableIterator iterator(*this);
  182.   while (!iterator.done() && success)               // For each object.
  183.     success = iterator.next()->writeObject(file);   // Write object.
  184.   return success;
  185. }
  186.  
  187.  
  188. // "read" reads the array objects from the specified reserve file.
  189. //
  190. Bool CmHashTable::read(CmReserveFile& file)
  191. {
  192.   unsigned size = readBase(file);                 // Read base container.
  193.  
  194.   int total;
  195.   if (!file.read(total)) return FALSE;            // Read number of objects.
  196.   if (!resize(size))     return FALSE;            // Resize the table.
  197.  
  198.   removeAll();
  199.  
  200.   Bool success = TRUE;
  201.   int  ii      = 0;
  202.   while (ii < total && success)                   // For each object,
  203.   {
  204.     CmObject *pObj = CmObject::readObject(file);  // Read object.
  205.     if (pObj) success = add(pObj); ii++;          // Add to table.
  206.   }
  207.   return success;
  208. }
  209.  
  210.  
  211. // "append" adds a new object to the end of this hash bucket.
  212. //
  213. Bool CmHashBucket::append(CmObject* pObj)
  214. {
  215.   CmHashNode *newnode = new CmHashNode(pObj);
  216.   if (!newnode) return FALSE;
  217.  
  218.   if (!_first)
  219.     _first = _last = newnode;
  220.   else
  221.   {
  222.     _last->_next = newnode;
  223.     _last        = newnode;
  224.   }
  225.   _size++;
  226.   return TRUE;
  227. }
  228.  
  229.  
  230. // "contains" checks to see if an object that isEqual to the specified
  231. // object exists in the bucket.
  232. //
  233. Bool CmHashBucket::contains(CmObject* pObj) const
  234. {
  235.   CmHashNode *rover = _first;
  236.   Bool        found = FALSE;
  237.   while (rover && !found)
  238.   {
  239.     if (rover->_data->isEqual(pObj)) found = TRUE;
  240.     else                             rover = rover->_next;
  241.   }
  242.   return found;
  243. }
  244.  
  245.  
  246. // "remove" removes the first occurrence of an object that isEqual
  247. // to the specified object from the bucket.
  248. //
  249. Bool CmHashBucket::remove(CmObject* pObj, Bool delFlag)
  250. {
  251.   if (!pObj || !_first) return FALSE;
  252.  
  253.   if (_first->_data->isEqual(pObj))         // Object is first in the list.
  254.   {
  255.     CmHashNode *temp = _first;
  256.     if (_first == _last) _first = _last = NULL;
  257.     else                 _first = _first->_next;
  258.     _size--;
  259.     if (delFlag) delete temp->_data;
  260.     delete temp;
  261.     return TRUE;
  262.   }
  263.  
  264.   CmHashNode *rover1 = _first;              // Search for object in list.
  265.   CmHashNode *rover2 = _last;
  266.  
  267.   while (rover1 != NULL && !(rover1->_data->isEqual(pObj)))
  268.   {
  269.     rover2 = rover1;
  270.     rover1 = rover1->_next;
  271.   }
  272.  
  273.   if (rover1 == NULL) return FALSE;         // Object was not found.
  274.  
  275.   if (rover1 == _last)                      // Object is last in list.
  276.   {
  277.     _last         = rover2;
  278.     rover2->_next = NULL;
  279.   }
  280.  
  281.   else                                      // Remove object from list.
  282.     rover2->_next = rover2->_next->_next;
  283.  
  284.   if (delFlag) delete rover1->_data;        // Delete object (if requested)
  285.   delete rover1;                            // and delete the hash node.
  286.   return TRUE;
  287. }
  288.  
  289.  
  290. // "lookup" returns the first occurrence of an object which isEqual
  291. // to the specified object.
  292. //
  293. CmObject* CmHashBucket::lookup(CmObject* pObj) const
  294. {
  295.   CmHashNode *rover = _first;
  296.   Bool        found = FALSE;
  297.   while (rover && !found)
  298.   {
  299.     if (rover->_data->isEqual(pObj)) found = TRUE;
  300.     else                             rover = rover->_next;
  301.   }
  302.  
  303.   return (found) ? rover->_data : NULL;
  304. }
  305.  
  306.  
  307. // "removeAll" removes all objects from this list and deletes the objects
  308. // if requested to do so.
  309. //
  310. void CmHashBucket::removeAll(Bool delFlag)
  311. {
  312.   CmHashNode *temp, *rover = _first;
  313.   while (rover)
  314.   {
  315.     temp = rover->_next;
  316.     if (delFlag) delete rover->_data;
  317.     delete rover;
  318.     rover = temp;
  319.   }
  320.   _size  = 0;
  321.   _first = _last = NULL;
  322. }
  323.  
  324.  
  325. // "CmHashTableIterator" is the iterator constructor.
  326. //
  327. CmHashTableIterator::CmHashTableIterator(const CmHashTable& T)
  328.                     : _table(T), _bucket(0), _node(NULL)
  329. {
  330.   while (_table._buckets[_bucket]._size == 0 && _bucket < _table._size)
  331.     _bucket++;
  332.   if (_bucket < _table._size) _node = _table._buckets[_bucket]._first;
  333. }
  334.  
  335.  
  336. // "next" returns the current object pointed to by the iterator and
  337. // then advances the iterator to the next object.
  338. //
  339. CmObject* CmHashTableIterator::next()
  340. {
  341.   if (!_node) return NULL;
  342.  
  343.   CmObject *pObj = _node->_data;
  344.  
  345.   if (_node->_next)
  346.     _node = _node->_next;
  347.   else
  348.   {
  349.     _bucket++;
  350.     while (_bucket < _table._size && _table._buckets[_bucket]._size == 0)
  351.       _bucket++;
  352.     _node = (_bucket < _table._size) ? _table._buckets[_bucket]._first : NULL;
  353.   }
  354.   return pObj;
  355. }
  356.  
  357.  
  358. // "previous" decrements the iterator by one object and then returns
  359. // that object.
  360. //
  361. CmObject* CmHashTableIterator::previous()
  362. {
  363.   if (!_node) return NULL;
  364.   CmObject *rval = _node->_data;
  365.  
  366.   if (_node == _table._buckets[_bucket]._first)
  367.   {
  368.     --_bucket;
  369.     while (_bucket >= 0 && _table._buckets[_bucket]._size == 0) _bucket--;
  370.     _node = (_bucket >= 0) ? _table._buckets[_bucket]._last : NULL;
  371.   }
  372.   else
  373.   {
  374.     CmHashNode *rover = _table._buckets[_bucket]._first;
  375.     while (rover && rover->_next != _node)
  376.       rover = rover->_next;
  377.     _node = rover;
  378.   }
  379.   return rval;
  380. }
  381.  
  382.  
  383. // "first" moves the iterator to the first object in the table.
  384. //
  385. void CmHashTableIterator::first()
  386. {
  387.   _bucket = 0;
  388.   _node   = NULL;
  389.   while (_table._buckets[_bucket]._size == 0 && _bucket < _table._size)
  390.     _bucket++;
  391.   if (_bucket < _table._size) _node = _table._buckets[_bucket]._first;
  392. }
  393.  
  394.  
  395. // "last" moves the iterator to the last object in the table.
  396. //
  397. void CmHashTableIterator::last()
  398. {
  399.   _bucket = _table._size - 1;
  400.   _node   = NULL;
  401.   while (_bucket >= 0 && _table._buckets[_bucket]._size == 0)
  402.     _bucket--;
  403.   if(_bucket >= 0) _node = _table._buckets[_bucket]._last;
  404. }
  405.